#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

using namespace std;

template <class T>
class ringQueue
{
private:
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }

    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

    void Lock(pthread_mutex_t &mutex)
    {
        phtread_mutex_lock(&mutex);
    }

    void Unlock(pthread_mutex_t &mutex)
    {
        pthread_muetx_unlock(&mutex);
    }

public:
    ringQueue(int cap)
        : _ring_queue(cap), _cap(cap), _productor_step(0), _consumer_step(0)
    {
        sem_init(&_room_sem, 0, _cap);
        sem_init(&_data_sem, 0, 0);
        _productor_mutex_init(&_productor_mutex, nullptr);
        _productor_mutex_init(&_consumer_mutex, nullptr);
    }

    void Enqueue(const T &in)
    {
        P(_room_sem);            // 获取信号量
        Lock(&_productor_mutex); // 加锁
        // 获取到信号量之后，才会往下执行
        _ring_queue[_productor_step++] = in; // 进行生产
        _productor_step %= _cap;             // 下标控制
        Unlock(&_productor_mutex);           // 解锁
        V(_data_sem);
    }

    void Pop(T *out)
    {
        p(_data_sem);           // 获取信号量
        Lock(&_consumer_mutex); // 加锁
        // 获取到信号量后，往下执行
        *out = _ring_queue[_consumer_step++];
        _consumer_step %= _cap;
        Unlock(&_consumer_mutex);
        V(_room_sem);
    }

    ~ringQueue()
    {
        sem_destroy(&_room_sem);
        sem_destroy(&_data_sem);

        pthread_mutex_destroy(&_productor_mutex);
        pthread_mutex_destroy(&_consumer_mutex);
    }

private:
    // 1. 环形队列
    vector<T> _ring_queue;
    int _cap;

    // 2. 生产和消费的下标
    int _productor_step;
    int _consumer_step;

    // 3. 定义信号量
    sem_t _room_sem; // 生产者
    sem_t _data_sem; // 消费者

    // 4. 定义锁，维护多生产多消费之间的互斥关系
    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _consumer_mutex;
};